{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "99adcd5d-ffed-4053-8bc1-3d4143381b61",
   "metadata": {},
   "source": [
    "# 数据集准备与加载"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cf7343c8-4b66-4f98-b8a2-33c7e79ef2d5",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating data folder...\n",
      "Downloading data from https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz (162.2 MB)\n",
      "\n",
      "file_sizes: 100%|████████████████████████████| 170M/170M [00:03<00:00, 45.9MB/s]\n",
      "Extracting tar.gz file...\n",
      "Successfully downloaded / unzipped to ./datasets-cifar10-bin\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'./datasets-cifar10-bin'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from download import download\n",
    "\n",
    "url = \"https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz\"\n",
    "\n",
    "download(url, \"./datasets-cifar10-bin\", kind=\"tar.gz\", replace=True)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f59a252f-7235-4c3c-9bf7-56dfba35e3c8",
   "metadata": {
    "tags": []
   },
   "source": [
    "### 导入相关库，加载数据集，进行图像增强操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ecdae312-e918-4e55-a094-72321cde669e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/mindspore/miniconda/envs/jupyter/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.\n",
      "  setattr(self, word, getattr(machar, word).flat[0])\n",
      "/home/mindspore/miniconda/envs/jupyter/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.\n",
      "  return self._float_to_str(self.smallest_subnormal)\n",
      "/home/mindspore/miniconda/envs/jupyter/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.\n",
      "  setattr(self, word, getattr(machar, word).flat[0])\n",
      "/home/mindspore/miniconda/envs/jupyter/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.\n",
      "  return self._float_to_str(self.smallest_subnormal)\n"
     ]
    }
   ],
   "source": [
    "import mindspore as ms\n",
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.vision as vision\n",
    "import mindspore.dataset.transforms as transforms\n",
    "from mindspore import dtype as mstype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ce4866da-54a9-4cf0-98a8-c6e4758dae2e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "data_dir = \"./datasets-cifar10-bin/cifar-10-batches-bin\"  # 数据集根目录\n",
    "batch_size = 256  # 批量大小\n",
    "image_size = 32  # 训练图像空间大小\n",
    "workers = 4  # 并行线程个数\n",
    "num_classes = 10  # 分类数量\n",
    "\n",
    "\n",
    "def create_dataset_cifar10(dataset_dir, usage, resize, batch_size, workers):\n",
    "\n",
    "    data_set = ds.Cifar10Dataset(dataset_dir=dataset_dir,\n",
    "                                 usage=usage,\n",
    "                                 num_parallel_workers=workers,\n",
    "                                 shuffle=True)\n",
    "\n",
    "    trans = []\n",
    "    if usage == \"train\":\n",
    "        trans += [\n",
    "            vision.RandomCrop((32, 32), (4, 4, 4, 4)),\n",
    "            vision.RandomHorizontalFlip(prob=0.5)\n",
    "        ]\n",
    "\n",
    "    trans += [\n",
    "        vision.Resize(resize),\n",
    "        vision.Rescale(1.0 / 255.0, 0.0),\n",
    "        vision.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]),\n",
    "        vision.HWC2CHW()\n",
    "    ]\n",
    "\n",
    "    target_trans = transforms.TypeCast(mstype.int32)\n",
    "\n",
    "    # 数据映射操作\n",
    "    data_set = data_set.map(operations=trans,\n",
    "                            input_columns='image',\n",
    "                            num_parallel_workers=workers)\n",
    "\n",
    "    data_set = data_set.map(operations=target_trans,\n",
    "                            input_columns='label',\n",
    "                            num_parallel_workers=workers)\n",
    "\n",
    "    # 批量操作\n",
    "    data_set = data_set.batch(batch_size)\n",
    "\n",
    "    return data_set\n",
    "\n",
    "\n",
    "# 获取处理后的训练与测试数据集\n",
    "\n",
    "dataset_train = create_dataset_cifar10(dataset_dir=data_dir,\n",
    "                                       usage=\"train\",\n",
    "                                       resize=image_size,\n",
    "                                       batch_size=batch_size,\n",
    "                                       workers=workers)\n",
    "step_size_train = dataset_train.get_dataset_size()\n",
    "\n",
    "dataset_val = create_dataset_cifar10(dataset_dir=data_dir,\n",
    "                                     usage=\"test\",\n",
    "                                     resize=image_size,\n",
    "                                     batch_size=batch_size,\n",
    "                                     workers=workers)\n",
    "step_size_val = dataset_val.get_dataset_size()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "163cf52a-49fb-42a8-a768-ffdb19dcb34b",
   "metadata": {},
   "source": [
    "### 对CIFAR-10训练数据集进行可视化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "597237b4-32cc-43bd-8e5c-590f267d5a4e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "aaecd56c-2b90-4b17-b303-85d2c9b11a6f",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Image shape: (256, 3, 32, 32), Label shape: (256,)\n",
      "Labels: [9 3 8 2 3 4]\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAGFCAYAAABg2vAPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8ekN5oAAAACXBIWXMAAA9hAAAPYQGoP6dpAABvmklEQVR4nO29eZSdV3nm+37DmYc6NapUGqpKgyVLlmcbMLYFTsB2B9MOg5vQ3RiSbkOMs5qVkM7qpMHGCfRtSDq3Q8ICbgjcXEivbpxuEocwhsEYDPEkW7KswZqtkmo+VafO/A33j15W593PNi7AUkl8z28t1mJvv+cb995n13kfPa8Tx3EshBBCCEks7kpfACGEEEJWFm4GCCGEkITDzQAhhBCScLgZIIQQQhIONwOEEEJIwuFmgBBCCEk43AwQQgghCYebAUIIISThcDNACCGEJBxuBlaQ++67TxzHkZmZmZW+FEIIOW95zWteI5dccslLxh09elQcx5HPfe5zZ/+ifs5I9GbgBz/4gdx3331SrVZX+lIIOW+ZmJiQ++67T3bt2rXSl0IIOUskfjPwoQ99iJsBQn4MExMT8qEPfYibAXLeMzo6Ks1mU/71v/7XK30pFxyJ3gwslyiKpNVqrfRlEEII+TE4jiPZbFY8z1vpS7ngSOxm4L777pPf/u3fFhGR8fFxcRxHHMc5k3O655575Atf+IJs375dMpmMfPWrX5XvfOc74jiOfOc731HHerE81b59++SOO+6QwcFByeVysmXLFvm93/u9H3tdx44dk02bNskll1wik5OTL+ctkwRy8uRJ+bVf+zUZGRmRTCYj4+Pj8uu//uvS6XRkbm5O3v/+98uOHTukWCxKuVyWW2+9VZ566qkzn//Od74j11xzjYiIvOtd7zozT5iTJS8ntVpN3ve+98nY2JhkMhkZGhqS173udfLEE0+ouL1798prX/tayefzsmbNGvnoRz+q/rttLX7nO98pxWJRDh8+LDfffLMUCgUZGRmR+++/X1i09//gr/QFrBRvetOb5MCBA/Lf/tt/kz/+4z+WgYEBEREZHBwUEZFvfetb8j/+x/+Qe+65RwYGBmRsbOwnSic8/fTTcsMNN0gqlZK77rpLxsbG5NChQ/Lggw/Khz/8YetnDh06JDfddJP09fXJN77xjTPXRMhPw8TEhFx77bVSrVblrrvukq1bt8rJkyflgQcekEajIYcPH5YvfelL8ta3vlXGx8dlcnJSPvWpT8nOnTtl7969MjIyIhdffLHcf//98sEPflDuuusuueGGG0RE5LrrrlvhuyM/T7znPe+RBx54QO655x7Ztm2bzM7OysMPPyzPPvusXHnllSIiMj8/L7fccou86U1vkjvuuEMeeOAB+Z3f+R3ZsWOH3HrrrT/2+GEYyi233CKvfOUr5aMf/ah89atflXvvvVeCIJD777//XNzi+U+cYD72sY/FIhIfOXJE9YtI7Lpu/Mwzz6j+b3/727GIxN/+9rdV/5EjR2IRiT/72c+e6bvxxhvjUqkUHzt2TMVGUXTm/997772xiMTT09Pxs88+G4+MjMTXXHNNPDc397LcH0k273jHO2LXdeNHH30U/lsURXGr1YrDMFT9R44ciTOZTHz//fef6Xv00UdhfBPyctLT0xO/973vfdH/vnPnzlhE4r/8y78809dut+Ph4eH4zW9+85k+21p85513xiIS/8Zv/MaZviiK4l/6pV+K0+l0PD09/fLezAVKYtMEL8XOnTtl27ZtP9Vnp6en5aGHHpJf/dVflfXr16v/5jgOxO/Zs0d27twpY2Nj8s1vflN6e3t/qvMS8gJRFMmXvvQlue222+Tqq6+G/+44jmQyGXHd/70EhGEos7OzUiwWZcuWLfDzLCFnk0qlIj/60Y9kYmLiRWOKxaL8q3/1r8600+m0XHvttXL48OFlneOee+458/9fSAV3Oh355je/+dNf+M8R3Ay8COPj4z/1Z18YnMv5d7EiIrfddpuUSiX52te+JuVy+ac+LyEvMD09LYuLiz92DEZRJH/8x38smzdvlkwmIwMDAzI4OChPP/20LCwsnMOrJUnnox/9qOzZs0fWrVsn1157rdx3333wJb927Vr4Y6q3t1fm5+df8viu68qGDRtU30UXXSQi/1tnQLgZeFFyuRz02f6qF/nff1X9LLz5zW+WQ4cOyRe+8IWf6TiE/CR85CMfkd/8zd+UG2+8UT7/+c/L1772NfnGN74h27dvlyiKVvrySIK444475PDhw/Lxj39cRkZG5GMf+5hs375dvvKVr5yJebF/IRBTBPiykFgBociLf7m/GC/8fG8KCY8dO6baL+xA9+zZs6zjfuxjHxPf9+Xuu++WUqkkb3/723+i6yLEZHBwUMrl8o8d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",
      "text/plain": [
       "<Figure size 640x480 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 获取训练集一个批次的数据\n",
    "data_iter = next(dataset_train.create_dict_iterator())\n",
    "\n",
    "# 提取图像和标签并转为numpy数组\n",
    "images = data_iter[\"image\"].asnumpy()\n",
    "labels = data_iter[\"label\"].asnumpy()\n",
    "\n",
    "# 打印数据形状和前6个标签\n",
    "print(f\"Image shape: {images.shape}, Label shape: {labels.shape}\")\n",
    "print(f\"Labels: {labels[:6]}\")\n",
    "\n",
    "# 读取类别名称\n",
    "classes = []\n",
    "with open(data_dir + \"/batches.meta.txt\", \"r\") as f:\n",
    "    for line in f:\n",
    "        line = line.rstrip()\n",
    "        if line:\n",
    "            classes.append(line)\n",
    "\n",
    "# 显示前6张图片\n",
    "plt.figure()\n",
    "for i in range(6):\n",
    "    plt.subplot(2, 3, i + 1)\n",
    "    # 转换维度为(高,宽,通道)\n",
    "    image_trans = np.transpose(images[i], (1, 2, 0))\n",
    "    # 反标准化（恢复像素值）\n",
    "    mean = np.array([0.4914, 0.4822, 0.4465])\n",
    "    std = np.array([0.2023, 0.1994, 0.2010])\n",
    "    image_trans = std * image_trans + mean\n",
    "    image_trans = np.clip(image_trans, 0, 1)  # 限制像素范围\n",
    "    plt.title(classes[labels[i]])  # 显示类别名称\n",
    "    plt.imshow(image_trans)\n",
    "    plt.axis(\"off\")  # 隐藏坐标轴\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0a49657-09f5-4d1d-b9c4-4e8b7f7a76af",
   "metadata": {},
   "source": [
    "# 构建网络"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91a723ac-3baa-49a2-96c2-1eed24c76dd9",
   "metadata": {},
   "source": [
    "### 实现Building Block结构"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "dcc3677e-90bd-4f87-a52a-ef2d8669101c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from typing import Type, Union, List, Optional\n",
    "import mindspore.nn as nn\n",
    "from mindspore.common.initializer import Normal"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0546b72a-10ce-42b0-929f-51c008a53e50",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 初始化权重参数：均值为0，标准差为0.02的正态分布\n",
    "weight_init = Normal(mean=0, sigma=0.02)\n",
    "# 初始化BatchNorm层的gamma参数：均值为1，标准差为0.02的正态分布\n",
    "gamma_init = Normal(mean=1, sigma=0.02)\n",
    "\n",
    "class ResidualBlockBase(nn.Cell):\n",
    "    expansion: int = 1  # 扩展系数：最后一个卷积层输出通道数与第一个保持一致\n",
    "\n",
    "    def __init__(self, in_channel: int, out_channel: int,\n",
    "                 stride: int = 1, norm: Optional[nn.Cell] = None,\n",
    "                 down_sample: Optional[nn.Cell] = None) -> None:\n",
    "        \"\"\"\n",
    "            in_channel: 输入特征图的通道数\n",
    "            out_channel: 输出特征图的通道数\n",
    "            stride: 卷积步长，默认为1\n",
    "            norm: 归一化层，默认为None\n",
    "            down_sample: 下采样模块，默认为None\n",
    "        \"\"\"\n",
    "        super(ResidualBlockBase, self).__init__()\n",
    "        # 若未指定归一化层，则默认使用BatchNorm2d\n",
    "        if not norm:\n",
    "            self.norm = nn.BatchNorm2d(out_channel)\n",
    "        else:\n",
    "            self.norm = norm\n",
    "\n",
    "        # 主分支第一层卷积：3x3卷积核，指定步长和初始化权重\n",
    "        self.conv1 = nn.Conv2d(in_channel, out_channel,\n",
    "                               kernel_size=3, stride=stride,\n",
    "                               weight_init=weight_init)\n",
    "        # 主分支第二层卷积：3x3卷积核，步长默认1\n",
    "        self.conv2 = nn.Conv2d(in_channel, out_channel,\n",
    "                               kernel_size=3, weight_init=weight_init)\n",
    "        self.relu = nn.ReLU()  # ReLU激活函数\n",
    "        self.down_sample = down_sample  # 下采样模块\n",
    "\n",
    "    def construct(self, x):\n",
    "        identity = x  # shortcut分支：保存输入作为残差连接的基准\n",
    "\n",
    "        # 主分支计算\n",
    "        out = self.conv1(x)  # 第一层卷积\n",
    "        out = self.norm(out)  # 归一化\n",
    "        out = self.relu(out)  # 激活\n",
    "        out = self.conv2(out)  # 第二层卷积\n",
    "        out = self.norm(out)  # 归一化\n",
    "\n",
    "        # 若存在下采样模块，对shortcut分支进行维度调整\n",
    "        if self.down_sample is not None:\n",
    "            identity = self.down_sample(x)\n",
    "\n",
    "        out += identity  # 主分支与shortcut分支相加\n",
    "        out = self.relu(out)  # 最终激活\n",
    "\n",
    "        return out"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fea0a050-2f80-41c2-9f7e-3115c2bc4b42",
   "metadata": {},
   "source": [
    "### 实现Bottleneck结构"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "9293315d-5e29-4639-b813-c9ba5f878503",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "class ResidualBlock(nn.Cell):\n",
    "    expansion = 4  # 扩展系数：最后一个卷积层输出通道数是第一个的4倍\n",
    "\n",
    "    def __init__(self, in_channel: int, out_channel: int,\n",
    "                 stride: int = 1, down_sample: Optional[nn.Cell] = None) -> None:\n",
    "        \"\"\"\n",
    "            in_channel: 输入特征图的通道数\n",
    "            out_channel: 中间卷积层的输出通道数（最终输出为out_channel*expansion）\n",
    "            stride: 第二层卷积的步长，用于控制特征图尺寸，默认为1\n",
    "            down_sample: 下采样模块（用于调整shortcut分支维度以匹配主分支），默认为None\n",
    "        \"\"\"\n",
    "        super(ResidualBlock, self).__init__()\n",
    "\n",
    "        # 主分支第一层：1x1卷积\n",
    "        self.conv1 = nn.Conv2d(in_channel, out_channel,\n",
    "                               kernel_size=1, weight_init=weight_init)\n",
    "        self.norm1 = nn.BatchNorm2d(out_channel)  # 第一层卷积后的批归一化\n",
    "\n",
    "        # 主分支第二层：3x3卷积\n",
    "        self.conv2 = nn.Conv2d(out_channel, out_channel,\n",
    "                               kernel_size=3, stride=stride,\n",
    "                               weight_init=weight_init)\n",
    "        self.norm2 = nn.BatchNorm2d(out_channel)  # 第二层卷积后的批归一化\n",
    "\n",
    "        # 主分支第三层：1x1卷积\n",
    "        self.conv3 = nn.Conv2d(out_channel, out_channel * self.expansion,\n",
    "                               kernel_size=1, weight_init=weight_init)\n",
    "        self.norm3 = nn.BatchNorm2d(out_channel * self.expansion)  # 第三层卷积后的批归一化\n",
    "\n",
    "        self.relu = nn.ReLU()  # ReLU激活函数\n",
    "        self.down_sample = down_sample  # 下采样模块\n",
    "\n",
    "    def construct(self, x):\n",
    "        \"\"\"扩展残差块前向传播逻辑\"\"\"\n",
    "        identity = x  # shortcut分支：保存输入作为残差连接的基准\n",
    "\n",
    "        # 主分支计算（1x1卷积 -> 批归一化 -> 激活 -> 3x3卷积 -> 批归一化 -> 激活 -> 1x1卷积 -> 批归一化）\n",
    "        out = self.conv1(x)\n",
    "        out = self.norm1(out)\n",
    "        out = self.relu(out)\n",
    "\n",
    "        out = self.conv2(out)\n",
    "        out = self.norm2(out)\n",
    "        out = self.relu(out)\n",
    "\n",
    "        out = self.conv3(out)\n",
    "        out = self.norm3(out)\n",
    "\n",
    "        # 若存在下采样模块，对shortcut分支进行维度调整\n",
    "        if self.down_sample is not None:\n",
    "            identity = self.down_sample(x)\n",
    "\n",
    "        out += identity  # 主分支与shortcut分支相加\n",
    "        out = self.relu(out)  # 最终激活\n",
    "\n",
    "        return out"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d720a5bd-de5b-45bf-aade-8a1c0e9d1589",
   "metadata": {},
   "source": [
    "### 构建ResNet50网络"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c63e409-4f14-4ff0-bea2-2123bf386723",
   "metadata": {},
   "source": [
    "#### 残差块的构建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "53f5433e-f354-4150-bff3-d82860ec5d42",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def make_layer(last_out_channel, block: Type[Union[ResidualBlockBase, ResidualBlock]],\n",
    "               channel: int, block_nums: int, stride: int = 1):\n",
    "    \"\"\"\n",
    "        last_out_channel: 上一层输出的特征图通道数\n",
    "        block: 残差块类型（基础残差块ResidualBlockBase或扩展残差块ResidualBlock）\n",
    "        channel: 残差块中中间卷积层的通道数（最终输出通道数为channel * block.expansion）\n",
    "        block_nums: 该层中残差块的堆叠数量\n",
    "        stride: 第一个残差块的卷积步长（用于控制特征图尺寸缩减），默认为1\n",
    "    \"\"\"\n",
    "    down_sample = None  # 初始化下采样模块\n",
    "\n",
    "    # 当步长不为1，或输入输出通道数不匹配时，创建下采样模块\n",
    "    if stride != 1 or last_out_channel != channel * block.expansion:\n",
    "        # 下采样模块：1x1卷积+ 批归一化\n",
    "        down_sample = nn.SequentialCell([\n",
    "            nn.Conv2d(last_out_channel, channel * block.expansion,\n",
    "                      kernel_size=1, stride=stride, weight_init=weight_init),\n",
    "            nn.BatchNorm2d(channel * block.expansion, gamma_init=gamma_init)\n",
    "        ])\n",
    "\n",
    "    layers = []\n",
    "    # 添加第一个残差块\n",
    "    layers.append(block(last_out_channel, channel, stride=stride, down_sample=down_sample))\n",
    "\n",
    "    # 更新当前输入通道数\n",
    "    in_channel = channel * block.expansion\n",
    "    # 堆叠剩余的残差块\n",
    "    for _ in range(1, block_nums):\n",
    "        layers.append(block(in_channel, channel))  # 输入输出通道已匹配，无需下采样\n",
    "\n",
    "    # 将所有残差块组合为一个顺序执行的网络层并返回\n",
    "    return nn.SequentialCell(layers)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02e29cd5-e5ef-4224-80bc-a1c6769d4673",
   "metadata": {},
   "source": [
    "#### ResNet50模型的构建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "bea835fb-b5d0-455a-9bc9-91f21efc2d8b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from mindspore import load_checkpoint, load_param_into_net\n",
    "\n",
    "\n",
    "class ResNet(nn.Cell):\n",
    "    def __init__(self, block: Type[Union[ResidualBlockBase, ResidualBlock]],\n",
    "                 layer_nums: List[int], num_classes: int, input_channel: int) -> None:\n",
    "        super(ResNet, self).__init__()\n",
    "\n",
    "        self.relu = nn.ReLU()  # ReLU激活函数\n",
    "        # 第一个卷积层：输入3通道（彩色图），输出64通道，7x7卷积核，步长2\n",
    "        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, weight_init=weight_init)\n",
    "        self.norm = nn.BatchNorm2d(64)  # 批标准化层，作用于64通道\n",
    "        # 最大池化层：3x3池化核，步长2，same填充\n",
    "        self.max_pool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='same')\n",
    "\n",
    "        # 定义4个残差块组（通过make_layer函数构建）\n",
    "        self.layer1 = make_layer(64, block, 64, layer_nums[0])\n",
    "        self.layer2 = make_layer(64 * block.expansion, block, 128, layer_nums[1], stride=2)\n",
    "        self.layer3 = make_layer(128 * block.expansion, block, 256, layer_nums[2], stride=2)\n",
    "        self.layer4 = make_layer(256 * block.expansion, block, 512, layer_nums[3], stride=2)\n",
    "\n",
    "        self.avg_pool = nn.AvgPool2d()  # 平均池化层\n",
    "        self.flatten = nn.Flatten()  # 展平层\n",
    "        # 全连接层：输入为指定通道数，输出为分类数\n",
    "        self.fc = nn.Dense(in_channels=input_channel, out_channels=num_classes)\n",
    "\n",
    "    def construct(self, x):  # 前向传播过程\n",
    "        # 第一层：卷积 -> 标准化 -> 激活 -> 池化\n",
    "        x = self.conv1(x)\n",
    "        x = self.norm(x)\n",
    "        x = self.relu(x)\n",
    "        x = self.max_pool(x)\n",
    "\n",
    "        # 经过4个残差块组\n",
    "        x = self.layer1(x)\n",
    "        x = self.layer2(x)\n",
    "        x = self.layer3(x)\n",
    "        x = self.layer4(x)\n",
    "\n",
    "        # 池化 -> 展平 -> 全连接输出\n",
    "        x = self.avg_pool(x)\n",
    "        x = self.flatten(x)\n",
    "        x = self.fc(x)\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "5953f965-0825-4d3a-8999-30c6fff00609",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def _resnet(model_url: str, block: Type[Union[ResidualBlockBase, ResidualBlock]],\n",
    "            layers: List[int], num_classes: int, pretrained: bool, pretrained_ckpt: str,\n",
    "            input_channel: int):\n",
    "    # 创建ResNet模型实例\n",
    "    model = ResNet(block, layers, num_classes, input_channel)\n",
    "\n",
    "    # 如果需要加载预训练权重\n",
    "    if pretrained:\n",
    "        # 从指定URL下载预训练模型到本地路径\n",
    "        download(url=model_url, path=pretrained_ckpt, replace=True)\n",
    "        # 加载本地 checkpoint 文件中的参数\n",
    "        param_dict = load_checkpoint(pretrained_ckpt)\n",
    "        # 将参数加载到模型中\n",
    "        load_param_into_net(model, param_dict)\n",
    "\n",
    "    return model\n",
    "\n",
    "\n",
    "def resnet50(num_classes: int = 1000, pretrained: bool = False):\n",
    "    \"\"\"ResNet50模型定义\"\"\"\n",
    "    # ResNet50预训练模型的下载地址\n",
    "    resnet50_url = \"https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/models/application/resnet50_224_new.ckpt\"\n",
    "    # 预训练模型本地保存路径\n",
    "    resnet50_ckpt = \"./LoadPretrainedModel/resnet50_224_new.ckpt\"\n",
    "    # 调用_resnet函数构建ResNet50（使用ResidualBlock，残差块数量[3,4,6,3]，输入通道2048）\n",
    "    return _resnet(resnet50_url, ResidualBlock, [3, 4, 6, 3], num_classes,\n",
    "                   pretrained, resnet50_ckpt, 2048)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2735f2d1-6954-4047-9adc-4af8321a349c",
   "metadata": {},
   "source": [
    "# 模型训练与评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "0ebbb63a-0524-4bd5-a2f7-0ae8945f952c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading data from https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/models/application/resnet50_224_new.ckpt (97.7 MB)\n",
      "\n",
      "file_sizes: 100%|████████████████████████████| 102M/102M [00:01<00:00, 57.4MB/s]\n",
      "Successfully downloaded file to ./LoadPretrainedModel/resnet50_224_new.ckpt\n"
     ]
    }
   ],
   "source": [
    "# 定义ResNet50网络\n",
    "network = resnet50(pretrained=True)\n",
    "\n",
    "# 全连接层输入层的大小\n",
    "in_channel = network.fc.in_channels\n",
    "fc = nn.Dense(in_channels=in_channel, out_channels=10)\n",
    "# 重置全连接层\n",
    "network.fc = fc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "64b631ce-f830-458c-ab82-28804ba58b04",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 设置训练轮数\n",
    "num_epochs = 5\n",
    "# 定义余弦衰减学习率：最小学习率0.00001，最大学习率0.001\n",
    "# total_step为总训练步数（每轮步数×轮数），step_per_epoch为每轮步数\n",
    "lr = nn.cosine_decay_lr(min_lr=0.00001, max_lr=0.001, \n",
    "                        total_step=step_size_train * num_epochs,\n",
    "                        step_per_epoch=step_size_train, decay_epoch=num_epochs)\n",
    "\n",
    "# 定义优化器：Momentum优化器，使用上面定义的学习率，动量参数0.9\n",
    "opt = nn.Momentum(params=network.trainable_params(), learning_rate=lr, momentum=0.9)\n",
    "# 定义损失函数：带softmax的交叉熵损失，适用于稀疏标签，损失取平均值\n",
    "loss_fn = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')\n",
    "\n",
    "\n",
    "# 前向计算函数：输入数据和标签，返回模型输出和损失\n",
    "def forward_fn(inputs, targets):\n",
    "    logits = network(inputs)  # 模型预测输出\n",
    "    loss = loss_fn(logits, targets)  # 计算损失\n",
    "    return loss\n",
    "\n",
    "\n",
    "# 构建梯度计算函数：自动求导，关联优化器参数\n",
    "grad_fn = ms.value_and_grad(forward_fn, None, opt.parameters)\n",
    "\n",
    "\n",
    "# 单步训练函数：执行一次前向+反向传播+参数更新\n",
    "def train_step(inputs, targets):\n",
    "    loss, grads = grad_fn(inputs, targets)  # 计算损失和梯度\n",
    "    opt(grads)  # 用优化器更新参数\n",
    "    return loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "3ebebd19-3140-47eb-851e-4cf3a78c9319",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "# 创建迭代器\n",
    "data_loader_train = dataset_train.create_tuple_iterator(num_epochs=num_epochs)\n",
    "data_loader_val = dataset_val.create_tuple_iterator(num_epochs=num_epochs)\n",
    "\n",
    "# 最佳模型存储路径\n",
    "best_acc = 0\n",
    "best_ckpt_dir = \"./BestCheckpoint\"\n",
    "best_ckpt_path = \"./BestCheckpoint/resnet50-best.ckpt\"\n",
    "\n",
    "if not os.path.exists(best_ckpt_dir):\n",
    "    os.mkdir(best_ckpt_dir)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "77ac8769-2442-4796-a25d-75165e98e745",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import mindspore.ops as ops\n",
    "\n",
    "def train(data_loader, epoch):\n",
    "    \"\"\"模型训练函数\"\"\"\n",
    "    losses = []  # 存储每步损失\n",
    "    network.set_train(True)  # 设为训练模式\n",
    "\n",
    "    # 遍历训练数据\n",
    "    for i, (images, labels) in enumerate(data_loader):\n",
    "        loss = train_step(images, labels)  # 执行单步训练，得到损失\n",
    "        \n",
    "        # 每100步或最后一步打印训练信息\n",
    "        if i % 100 == 0 or i == step_size_train - 1:\n",
    "            print('Epoch: [%3d/%3d], Steps: [%3d/%3d], Train Loss: [%5.3f]' %\n",
    "                  (epoch + 1, num_epochs, i + 1, step_size_train, loss))\n",
    "        \n",
    "        losses.append(loss)  # 记录损失\n",
    "\n",
    "    # 返回本轮平均损失\n",
    "    return sum(losses) / len(losses)\n",
    "\n",
    "\n",
    "def evaluate(data_loader):\n",
    "    \"\"\"模型验证函数\"\"\"\n",
    "    network.set_train(False)  # 设为推理模式\n",
    "\n",
    "    correct_num = 0.0  # 正确预测的样本数\n",
    "    total_num = 0.0    # 总样本数\n",
    "\n",
    "    # 遍历验证数据\n",
    "    for images, labels in data_loader:\n",
    "        logits = network(images)  # 模型输出\n",
    "        pred = logits.argmax(axis=1)  # 取概率最大的类别作为预测结果\n",
    "        \n",
    "        # 计算正确预测数\n",
    "        correct = ops.equal(pred, labels).reshape((-1, ))  # 比较预测与标签\n",
    "        correct_num += correct.sum().asnumpy()  # 累加正确数\n",
    "        total_num += correct.shape[0]  # 累加总数\n",
    "\n",
    "    acc = correct_num / total_num  # 计算准确率\n",
    "    return acc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "e1181be2-51f0-4e9d-96b6-8a23c3699582",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Start Training Loop ...\n",
      "."
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/Ascend/ascend-toolkit/8.2.RC1/opp/built-in/op_impl/ai_core/tbe/impl/util/util_conv2d_dynamic.py:133: UserWarning: conv2d fmap ori_range changed from [[32, 2147483647], [2048, 2048], [1, 3], [1, 3]] to [[32, 2147483647], [2048, 2048], [1, 3], (1, 3)].\n",
      "  warnings.warn(to_print)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "........Epoch: [  1/  5], Steps: [  1/196], Train Loss: [2.395]\n",
      "Epoch: [  1/  5], Steps: [101/196], Train Loss: [1.477]\n",
      ".Epoch: [  1/  5], Steps: [196/196], Train Loss: [1.053]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/Ascend/ascend-toolkit/8.2.RC1/opp/built-in/op_impl/ai_core/tbe/impl/util/util_conv2d_dynamic.py:133: UserWarning: conv2d fmap ori_range changed from [[16, 31], [2048, 2048], [1, 3], [1, 3]] to [[16, 31], [2048, 2048], [1, 3], (1, 3)].\n",
      "  warnings.warn(to_print)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------------------------------------\n",
      "Epoch: [  1/  5], Average Train Loss: [1.616], Accuracy: [0.598]\n",
      "--------------------------------------------------\n",
      "Epoch: [  2/  5], Steps: [  1/196], Train Loss: [1.174]\n",
      "Epoch: [  2/  5], Steps: [101/196], Train Loss: [1.077]\n",
      "Epoch: [  2/  5], Steps: [196/196], Train Loss: [0.866]\n",
      "--------------------------------------------------\n",
      "Epoch: [  2/  5], Average Train Loss: [1.007], Accuracy: [0.686]\n",
      "--------------------------------------------------\n",
      "Epoch: [  3/  5], Steps: [  1/196], Train Loss: [0.942]\n",
      "Epoch: [  3/  5], Steps: [101/196], Train Loss: [0.799]\n",
      "Epoch: [  3/  5], Steps: [196/196], Train Loss: [0.909]\n",
      "--------------------------------------------------\n",
      "Epoch: [  3/  5], Average Train Loss: [0.850], Accuracy: [0.724]\n",
      "--------------------------------------------------\n",
      "Epoch: [  4/  5], Steps: [101/196], Train Loss: [0.652]\n",
      "Epoch: [  4/  5], Steps: [196/196], Train Loss: [0.654]\n",
      "--------------------------------------------------\n",
      "Epoch: [  4/  5], Average Train Loss: [0.769], Accuracy: [0.733]\n",
      "--------------------------------------------------\n",
      "Epoch: [  5/  5], Steps: [  1/196], Train Loss: [0.776]\n",
      "Epoch: [  5/  5], Steps: [101/196], Train Loss: [0.744]\n",
      "Epoch: [  5/  5], Steps: [196/196], Train Loss: [0.834]\n",
      "--------------------------------------------------\n",
      "Epoch: [  5/  5], Average Train Loss: [0.734], Accuracy: [0.741]\n",
      "--------------------------------------------------\n",
      "================================================================================\n",
      "End of validation the best Accuracy is:  0.741, save the best ckpt file in ./BestCheckpoint/resnet50-best.ckpt\n"
     ]
    }
   ],
   "source": [
    "# 开始循环训练\n",
    "print(\"Start Training Loop ...\")\n",
    "\n",
    "# 遍历每个训练轮次\n",
    "for epoch in range(num_epochs):\n",
    "    # 训练模型并获取本轮平均损失\n",
    "    curr_loss = train(data_loader_train, epoch)\n",
    "    # 在验证集上评估并获取准确率\n",
    "    curr_acc = evaluate(data_loader_val)\n",
    "\n",
    "    # 打印本轮训练结果\n",
    "    print(\"-\" * 50)\n",
    "    print(\"Epoch: [%3d/%3d], Average Train Loss: [%5.3f], Accuracy: [%5.3f]\" % (\n",
    "        epoch+1, num_epochs, curr_loss, curr_acc\n",
    "    ))\n",
    "    print(\"-\" * 50)\n",
    "\n",
    "    # 保存当前准确率最高的模型\n",
    "    if curr_acc > best_acc:\n",
    "        best_acc = curr_acc\n",
    "        ms.save_checkpoint(network, best_ckpt_path)\n",
    "\n",
    "# 训练结束，打印最佳验证结果\n",
    "print(\"=\" * 80)\n",
    "print(f\"End of validation the best Accuracy is: {best_acc: 5.3f}, \"\n",
    "      f\"save the best ckpt file in {best_ckpt_path}\", flush=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e5da346-7152-4efa-9742-1c493d4957b0",
   "metadata": {},
   "source": [
    "# 可视化模型预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "59a4cd1a-cb86-4a1a-9b14-6840f8f1175b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "\n",
    "def visualize_model(best_ckpt_path, dataset_val):\n",
    "    num_class = 10  # 分类类别数\n",
    "    # 创建ResNet50模型（10分类）\n",
    "    net = resnet50(num_class)\n",
    "    # 加载最佳模型的参数\n",
    "    param_dict = ms.load_checkpoint(best_ckpt_path)\n",
    "    ms.load_param_into_net(net, param_dict)\n",
    "    \n",
    "    # 获取验证集的一批数据\n",
    "    data = next(dataset_val.create_dict_iterator())\n",
    "    images = data[\"image\"]  # 图像数据\n",
    "    labels = data[\"label\"]  # 真实标签\n",
    "    \n",
    "    # 模型预测\n",
    "    output = net(data['image'])\n",
    "    pred = np.argmax(output.asnumpy(), axis=1)  # 取概率最大的类别作为预测结果\n",
    "\n",
    "    # 读取类别名称列表\n",
    "    classes = []\n",
    "    with open(data_dir + \"/batches.meta.txt\", \"r\") as f:\n",
    "        for line in f:\n",
    "            line = line.rstrip()  # 去除换行符\n",
    "            if line:  # 非空行添加到类别列表\n",
    "                classes.append(line)\n",
    "\n",
    "    # 显示6张图像及预测结果\n",
    "    plt.figure()\n",
    "    for i in range(6):\n",
    "        plt.subplot(2, 3, i + 1)  # 2行3列的子图布局\n",
    "        # 预测正确显示蓝色标题，错误显示红色\n",
    "        color = 'blue' if pred[i] == labels.asnumpy()[i] else 'red'\n",
    "        plt.title('predict:{}'.format(classes[pred[i]]), color=color)\n",
    "        \n",
    "        # 处理图像格式（转换通道顺序并反归一化）\n",
    "        picture_show = np.transpose(images.asnumpy()[i], (1, 2, 0))  # (C,H,W)转(H,W,C)\n",
    "        mean = np.array([0.4914, 0.4822, 0.4465])  # 均值\n",
    "        std = np.array([0.2023, 0.1994, 0.2010])   # 标准差\n",
    "        picture_show = std * picture_show + mean  # 反归一化\n",
    "        picture_show = np.clip(picture_show, 0, 1)  # 限制像素值在0-1之间\n",
    "        \n",
    "        plt.imshow(picture_show)  # 显示图像\n",
    "        plt.axis('off')  # 关闭坐标轴\n",
    "\n",
    "    plt.show()  # 显示图像\n",
    "\n",
    "\n",
    "# 使用验证数据集可视化模型预测结果\n",
    "visualize_model(best_ckpt_path=best_ckpt_path, dataset_val=dataset_val)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43b48175-476d-41e1-9708-7a69e72a70c1",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.23"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
